//
//  JJRequest.swift
//  swiftStudy
//
//  Created by hamilyjing on 2020/6/25.
//  Copyright © 2020 JJ. All rights reserved.
//

import Foundation

class JJRequest: JJBaseRequest {
    
    var identity: String?
    
    var userCacheDirectory: String?
    var sensitiveDataForSavedFileName: String?
    var parametersForSavedFileName: [String: Any]?
    
    var modelClassName: String! = "JJResponseBaseModel"
    
    var cacheModel: JJResponseBaseModelProtocol?
    var isSaveToMemory = false
    var isSaveToDisk = false
    
    var networkSuccessResponse: ((Any?, [String: Any]) -> Void)?
    var networkFailResponse: ((Any?, [String: Any]) -> Void)?
    
    var operation: ((JJResponseBaseModelProtocol?, JJResponseBaseModelProtocol?) -> JJResponseBaseModelProtocol?)?
    
    override init() {
       super.init()
    }
    
    init(identity: String?, parameters: [String: Any]?, isSaveToMemory: Bool, isSaveToDisk: Bool) {
        super.init()
        
        self.identity = identity
        
        self.requestParameters = parameters
        self.parametersForSavedFileName = parameters
        
        self.isSaveToMemory = isSaveToMemory
        self.isSaveToDisk = isSaveToDisk
        
        if parameters != nil {
            otherInfo["parameters"] = parameters!
        }
    }
    
    override func requestSuccessedFilter() -> Any? {
        let model = currentResponseModel()
        
        if !successForBussiness(model) {
            return model
        }
        
        if isSaveToMemory {
            cacheModel = model
        }
        
        if isSaveToDisk {
            saveModelToDiskCache(model)
        }
        
        return model
    }
    
    func currentResponseModel() -> JJResponseBaseModelProtocol? {
        var model = convertToModel()
        model = responseOperation(model, getCacheModel())
        return model
    }
    
    func convertToModel() -> JJResponseBaseModelProtocol? {
        return nil
    }
    
    func responseOperation(_ newModel_: JJResponseBaseModelProtocol?, _ oldModel_: JJResponseBaseModelProtocol?) -> JJResponseBaseModelProtocol? {
        if let responseOperation = operation {
            return responseOperation(newModel_, oldModel_)
        }
        
        return newModel_
    }
    
    func successForBussiness(_ model_: JJResponseBaseModelProtocol?) -> Bool {
        if model_ != nil {
            return model_!.successForBussiness()
        }
        return false
    }
    
    func getCacheModel() -> JJResponseBaseModelProtocol? {
        if cacheModel != nil {
            return cacheModel
        }
        
        let filePath = cacheFilePath()
        let data = FileManager.default.contents(atPath: filePath)
        if nil == data {
            return nil
        }
        
        let dataString = data!.jjs_string()
        if dataString == nil {
            return nil
        }
        
        let appName = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
        let modelClass = NSClassFromString(appName + "." + modelClassName) as! JJResponseBaseModelProtocol.Type
        let model = modelClass.deserialize(from: dataString!)
        
        if isSaveToMemory {
            cacheModel = model
        }
        
        return cacheModel
    }
    
    // MARK: -
    // MARK: cache file config
    
    func cacheFileDirectory() -> String {
        var cachesDirectory = FileManager.jjs_cachesDirectory()
        cachesDirectory += "/JJServiceManager"
        
        if let userCacheDirectory = self.userCacheDirectory {
            cachesDirectory += "/" + userCacheDirectory
        }
        
        let flag = FileManager.jjs_createDirectoryAtPath(path: cachesDirectory)
        assert(flag)
        
        return cachesDirectory
    }
    
    func cacheFileName() -> String {
        var cacheFileName = ""
        
        if let sensitiveData = sensitiveDataForSavedFileName {
            cacheFileName += sensitiveData + "_"
        } else {
            cacheFileName += "_"
        }
        
        if let identity = identity {
            cacheFileName += identity + "_"
        }
        
        let parameters = self.parametersForSavedFileName ?? [String: Any]()
        let parametersString = "Parameters:\(parameters)"
        let parametersStringMd5 = parametersString.jjs_md5String();
        cacheFileName += parametersStringMd5
        
        return cacheFileName
    }
    
    func cacheFilePath() -> String {
        return cacheFileDirectory() + "/" + cacheFileName()
    }
    
    func haveDiskCache() -> Bool {
        return FileManager.jjs_isFileExistAtPath(fileFullPath: cacheFilePath())
    }
    
    func saveModelToDiskCache(_ model_: JJResponseBaseModelProtocol?) -> Bool {
        guard model_ != nil else {
            return false
        }
        
        let filePath = cacheFilePath()
        let encodeString = model_!.encodeToString()
        guard encodeString != nil else {
            return false
        }
        
        do
        {
            try encodeString!.write(toFile: filePath, atomically: true, encoding: String.Encoding.utf8)
            return true
        }
        catch let error as NSError
        {
            assert(false, "error\(error.localizedDescription)")
            return false
        }
    }
    
    func removeMemoryCache() {
        cacheModel = nil
    }
    
    func removeDiskCache() {
        do{
            try FileManager.default.removeItem(atPath: cacheFilePath())
        } catch let error as NSError {
            assert(false, "error\(error.localizedDescription)")
        }
    }
    
    func removeAllCache() {
        removeMemoryCache()
        removeDiskCache()
    }
}
